
static const GLchar vertexShader[] =
   "varying vec3 vVertex; \n"
      "varying vec3 vNormal; \n"
         "void main(void) \n"
            "{ \n"
                    "vVertex = vec3(gl_ModelViewMatrix * gl_Vertex); \n"
                            "vNormal = normalize(gl_NormalMatrix * gl_Normal); \n"
                                    "gl_TexCoord[0] = gl_MultiTexCoord0; \n"
                                            "gl_Position = ftransform(); \n"
                                                "}";

static const GLchar fragmentShader[] = 
   "uniform vec3     amb; \n"
      "uniform vec3     diff; \n"
     "uniform vec3     spec; \n"
    "uniform float     rough; \n"
   "uniform int     glH_LightEnabled[gl_MaxLights]; \n"
      "varying vec3     vVertex; \n"
     "varying vec3     vNormal; \n"
    "void lightingModel( \n"
       "in vec3 nN, \n"
          "inout vec4 lAmb, \n"
         "inout vec4 lDiff, \n"
        "inout vec4 lSpec, \n"
       "in float sh \n"
      ") \n"
     "{ \n"
       "vec3    V = normalize(-vVertex); \n"
         "vec3 L, H; \n"
       "if (glH_LightEnabled[0] != 0) \n"
         "{ \n"
           "L = normalize(gl_LightSource[0].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
           "lAmb  += gl_LightSource[0].ambient; \n"
             "lDiff += gl_LightSource[0].diffuse * max(dot(nN, L), 0.0); \n"
           "lSpec += gl_LightSource[0].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
       "if (glH_LightEnabled[1] != 0) \n"
         "{ \n"
            "L = normalize(gl_LightSource[1].position.xyz - vVertex); \n"
           "H = normalize(V + L); \n"
              "lAmb  += gl_LightSource[1].ambient; \n"
             "lDiff += gl_LightSource[1].diffuse * max(dot(nN, L), 0.0); \n"
            "lSpec += gl_LightSource[1].specular * pow(max(dot(nN, H), 0.0), sh); \n"
      "} \n"
        "if (glH_LightEnabled[2] != 0) \n"
      "{ \n"
             "L = normalize(gl_LightSource[2].position.xyz - vVertex); \n"
            "H = normalize(V + L); \n"
           "lAmb  += gl_LightSource[2].ambient; \n"
              "lDiff += gl_LightSource[2].diffuse * max(dot(nN, L), 0.0); \n"
             "lSpec += gl_LightSource[2].specular * pow(max(dot(nN, H), 0.0), sh); \n"
       "} \n"
         "if (glH_LightEnabled[3] != 0) \n"
       "{ \n"
              "L = normalize(gl_LightSource[3].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
            "lAmb  += gl_LightSource[3].ambient; \n"
           "lDiff += gl_LightSource[3].diffuse * max(dot(nN, L), 0.0); \n"
              "lSpec += gl_LightSource[3].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
        "if (glH_LightEnabled[4] != 0) \n"
       "{ \n"
              "L = normalize(gl_LightSource[4].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
            "lAmb  += gl_LightSource[4].ambient; \n"
           "lDiff += gl_LightSource[4].diffuse * max(dot(nN, L), 0.0); \n"
              "lSpec += gl_LightSource[4].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
        "if (glH_LightEnabled[5] != 0) \n"
       "{ \n"
              "L = normalize(gl_LightSource[5].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
            "lAmb  += gl_LightSource[5].ambient; \n"
           "lDiff += gl_LightSource[5].diffuse * max(dot(nN, L), 0.0); \n"
              "lSpec += gl_LightSource[5].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
        "if (glH_LightEnabled[6] != 0) \n"
       "{ \n"
              "L = normalize(gl_LightSource[6].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
            "lAmb  += gl_LightSource[6].ambient; \n"
           "lDiff += gl_LightSource[6].diffuse * max(dot(nN, L), 0.0); \n"
              "lSpec += gl_LightSource[6].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
        "if (glH_LightEnabled[7] != 0) \n"
       "{ \n"
              "L = normalize(gl_LightSource[7].position.xyz - vVertex); \n"
             "H = normalize(V + L); \n"
            "lAmb  += gl_LightSource[7].ambient; \n"
           "lDiff += gl_LightSource[7].diffuse * max(dot(nN, L), 0.0); \n"
              "lSpec += gl_LightSource[7].specular * pow(max(dot(nN, H), 0.0), sh); \n"
         "} \n"
     "} \n"
    "void main (void) \n"
   "{ \n"
          "float   sh     = 1.0 / rough; \n"
         "vec3    nN     = normalize(vNormal); \n"
        "vec4    lAmb    = vec4(0.0, 0.0, 0.0, 1.0); \n"
       "vec4    lDiff   = vec4(0.0, 0.0, 0.0, 1.0); \n"
          "vec4    lSpec   = vec4(0.0, 0.0, 0.0, 1.0); \n"
         "lightingModel(nN, lAmb, lDiff, lSpec, sh); \n"
        "gl_FragColor.rgb = amb * gl_LightModel.ambient.rgb \n"
          "+ amb.rgb * lAmb.rgb \n"
            "+ diff * lDiff.rgb \n"
          "+ spec * lSpec.rgb; \n"
         "gl_FragColor.a = 1.0; \n"
    "} \n";
    
void 
checkInfoLog(GLuint object)
{
    GLint maxLength;
    GLint length;
    GLchar *infoLog;

    if (glIsProgram(object)) 
    {
        glGetProgramiv(object, GL_INFO_LOG_LENGTH, &maxLength);
    }
    else
    {
          glGetShaderiv(object, GL_INFO_LOG_LENGTH, &maxLength);
      }
    
    if (maxLength > 1)
    {
        infoLog = (GLchar *) malloc(maxLength);
        if (infoLog != NULL)
        {
              if (glIsShader(object)) 
              {
                  glGetShaderInfoLog(object, maxLength, &length, infoLog);
              }
              else 
              {
                glGetProgramInfoLog(object, maxLength, &length, infoLog);
              }
           
              // Print the information log here
              free(infoLog);
          }
    }
}


static void getProgramObject(void) 
{ 
    GLsizei length; 
    GLint vertexShaderCompiled = 0; 
    GLint fragmentShaderCompiled = 0; 
     
    if (1) { 
        // Initialize vertex shader. 
        vertexShaderObject = glCreateShader(GL_VERTEX_SHADER); 
        if (vertexShaderObject)  
        { 
              assert(GL_TRUE == glIsShader(vertexShaderObject)); 
              assert(GL_FALSE == glIsProgram(vertexShaderObject)); 
   
              length = (GLsizei) strlen(vertexShader); 
              glShaderSource(vertexShaderObject, 1, &vertexShader, &length); 
              glCompileShader(vertexShaderObject); 
              glGetShaderiv(vertexShaderObject, GL_COMPILE_STATUS, &vertexShaderCompiled); 
              CheckInfoLog(vertexShader, vertexShaderObject); 
          } 
    } 
 
    if (1) { 
        // Initialize fragment shader.
        fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
        if (fragmentShaderObject)
        {
            assert(GL_TRUE == glIsShader(fragmentShaderObject));
            assert(GL_FALSE == glIsProgram(fragmentShaderObject));

            length = (GLsizei) strlen(fragmentShader);
            glShaderSource(fragmentShaderObject, 1, &fragmentShader, &length);
            glCompileShader(fragmentShaderObject);
            glGetShaderiv(fragmentShaderObject, GL_COMPILE_STATUS, &fragmentShaderCompiled);
            CheckInfoLog(fragmentShader, fragmentShaderObject);
        }
    }

    // Initialize shader program.
    programObject = glCreateProgram();
    if (programObject)
    {
          GLint programLinked;

          assert(GL_FALSE == glIsShader(programObject));
          assert(GL_TRUE == glIsProgram(programObject));

          if (attachVertexShader && vertexShaderObject && vertexShaderCompiled) {
              glAttachShader(programObject, vertexShaderObject);
          }
          if (attachFragmentShader && fragmentShaderObject && fragmentShaderCompiled) {
              glAttachShader(programObject, fragmentShaderObject);
          }

          glLinkProgram(programObject);
          glGetProgramiv(programObject, GL_LINK_STATUS, &programLinked);
          CheckInfoLog("programObject", programObject);
      }
}

static void deleteProgramObject(void)
{
    glClearColor(0,0,0,0);

    if (programObject)
    {
        glUseProgram(0);
        if (vertexShaderObject) {
            glDetachShader(programObject, vertexShaderObject);
        }
        if (fragmentShaderObject) {
            glDetachShader(programObject, fragmentShaderObject);
        }
        glDeleteProgram(programObject);

        assert(GL_FALSE == glIsShader(programObject));
        assert(GL_FALSE == glIsProgram(programObject));

        programObject = 0;
    }

    if (vertexShaderObject)
    {
          glDeleteShader(vertexShaderObject);

          assert(GL_FALSE == glIsShader(vertexShaderObject));
          assert(GL_FALSE == glIsProgram(vertexShaderObject));

          vertexShaderObject = 0;
      }

    if (fragmentShaderObject)
    {
        glDeleteShader(fragmentShaderObject);

        assert(GL_FALSE == glIsShader(fragmentShaderObject));
        assert(GL_FALSE == glIsProgram(fragmentShaderObject));

        fragmentShaderObject = 0;
    }

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glColor3f(1.0f, 1.0f, 1.0f);
}
